<?php
// +----------------------------------------------------------------------
// | INPHP
// | Copyright (c) 2023 https://inphp.cc All rights reserved.
// | Licensed ( https://opensource.org/licenses/MIT )
// | Author: 幺月儿(https://gitee.com/lulanyin) Email: inphp@qq.com
// +----------------------------------------------------------------------
// | 
// +----------------------------------------------------------------------

//设置错误码
\Inphp\Core\Util\Error::set(include "error.php");

/**
 * 检测IP是否属于禁止的IP
 * @param string|null $ip
 * @return bool
 */
function checkIPDisable(?string $ip = null): bool {
    $ip = $ip ?? getIP();
    //IP黑名单
    $disableIP = \Inphp\Core\Modules::getModule("admin")->getConfig("disableIP");
    if (!empty($disableIP)) {
        $disableIPList = is_array($disableIP) ? $disableIP : explode(",", $disableIP);
        if (in_array($ip, $disableIPList)) {
            return true;
        }
        //支持*匹配
        foreach ($disableIPList as $disIP) {
            if (stripos($disIP, "*") > 0) {
                $disIP = substr($disIP, stripos($disIP, "*"));
            }
            if (stripos($disIP, $ip) === 0) {
                return true;
            }
        }
    }
    return false;
}

/**
 * 展示错误页面
 * @param string $message
 * @param string $title
 * @param string $status
 * @param array $vars
 * @throws SmartyException
 */
function showErrorPage(string $message, string $title = "遇到错误，无法执行", string $status = "404", array $vars = []): void {
    $response = getHttpResponse();
    if ($response->end) {
        return;
    }
    $smarty = \Inphp\Core\Middlewares\SmartyView::init();
    $smarty->assign("title", $title);
    $smarty->assign("message", $message);
    $smarty->assign("status", $status);
    if (!empty($vars)) {
        $smarty->assign($vars);
    }
    $defaultErrorPage = ROOT."/app/admin/view/admin/error.html";
    if ($module = \Inphp\Core\Modules::getModule()) {
        $errorPage = $module->http["view"]."/error.html";
        if (is_file($errorPage)) {
            $defaultErrorPage = $errorPage;
        }
    }
    if (is_file($defaultErrorPage)) {
        $response->withStatus(200)->withHtml($smarty->fetch($defaultErrorPage))->end();
    } else {
        $response->withStatus(200)->withText($title.(!empty($message) ? " ：{$message}" : ""))->end();
    }
}
//注册一个中间键，以方便特定事件处理
\Inphp\Core\Middlewares::push("showErrorPage", 'showErrorPage');

/**
 * 生成一个订单号
 * @return int
 */
function makeOrderId(): int {
    $date = date("Ymd");
    $keyName = "ID{$date}";
    //设置有效时间是一天，过期后，能自动清理
    $id = \Inphp\Core\Db\Redis::incr($keyName, 86400);
    return (int) $date.rand(10, 99).$id;
}

/**
 * 获取当前授权的用户信息
 * @return null|array
 */
function authUserInfo(): ?array {
    //客户端
    $client = getClient();
    if (!$client) {
        return null;
    }
    // 优先从 cookie -> session -> header
    $token = \Inphp\Core\Services\Http\Cookie::get("token", \Inphp\Core\Services\Http\Session::get("token"));
    if (empty($token)) {
        //从 header 中取
        $token = $client->header["TOKEN"] ?? null;
        if (empty($token)) {
            return null;
        }
    }
    //从redis获取缓存
    $uid = \Inphp\Core\Db\Redis::get("Token_{$token}");
    $uid = is_numeric($uid) ? ceil($uid) : 0;
    if ($uid === 0) {
        \Inphp\Core\Db\Redis::del("Token_{$token}");
        return null;
    }
    if ($uid < 0) {
        //查询超管配置
        $config = \Inphp\Core\Modules::getModule("admin")->getConfig("auth");
        $config = is_array($config) ? $config : [];
        $setUid = $config["uid"] ?? 0;
        if ($setUid != $uid) {
            \Inphp\Core\Db\Redis::del("Token_{$token}");
            return null;
        }
        //取账户数据
        return [
            "uid"           => $uid,
            "parentUid"     => 0,
            "parentsUid"    => null,
            "username"      => $config["username"],
            "countryCode"   => 86,
            "phone"         => null,
            "nickname"      => "超级管理员",
            "face"          => null,
            "registerTime"  => date("Y-m-d H:i:s"),
            "ip"            => getIP(),
            "groups"        => null,
            "state"         => 1,
            "admin"         => 1,
            "token"         => $token
        ];
    } elseif ($module = \Inphp\Core\Modules::getModule("sso")) {
        //
        //获取账号，防止账号被冻结了
        $user = \app\sso\model\UserModel::emptyQuery()
            ->where("uid", $uid)
            ->first();
        if (empty($user)) {
            \app\sso\model\UserAuthModel::dropToken($token);
            return null;
        }
        //账户状态
        if ($user["state"] == 0) {
            \app\sso\model\UserAuthModel::dropToken($token);
            return null;
        }
        $user["token"] = $token;
        $user["face"] = attachmentUrl($user["face"]);
        $user["nickname"] = \app\sso\model\UserModel::decodeNickname($user["nickname"]);
        //token时长处理
        $config = Inphp\Core\Modules::getModule("sso")?->getConfig("auth");
        $lifeTime = $config["tokenLifeTime"] ?? 0;
        $lifeTime = is_numeric($lifeTime) && $lifeTime >= 3600 ? ceil($lifeTime) : 0;
        //延长有效时长
        Inphp\Core\Db\Redis::set("Token_{$token}", $uid, $lifeTime > 0 ? $lifeTime : -1);
        //如果非跨域等客户端，给token延长一下时长
        if (!$client->cross) {
            Inphp\Core\Services\Http\Cookie::set("token", $token, $lifeTime > 0 ? $lifeTime : 90 * 86400);
        }
        return $user;
    }
    return null;
}

/**
 * 运行CMD
 * @param string $cmd
 * @param array $params
 * @param bool $background
 * @return array
 */
function CMD_RUN(string $cmd, array $params, bool $background = true): array {
    $php = \Inphp\Core\Modules::getModule("admin")->getConfig("php");
    $php = !empty($php) ? $php : "php";
    if (stripos($php, "php") < 0) {
        return ["PHP指令无效：{$php}", -1];
    }
    $cmd = "{$php} ".ROOT."/bin/cmd {$cmd}";
    foreach ($params as $key => $val) {
        $cmd .= " {$key}={$val}";
    }
    if ($background) {
        $cmd .= " > /dev/null 2>&1 &";
    }
    $bool = @exec($cmd, $output, $code);
    return [$output, $code, $cmd, $bool];
}